package com.atguigu.tingshu.common.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 登录切面类定义：校验的登录的状态
 *
 * @author Taeyang
 * @date 2025/4/25
 */
@Component
@Aspect
@Log4j2
public class LoginAspect {


    private final RedisTemplate redisTemplate;

    public LoginAspect(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    /**
     * 增强方法
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @SneakyThrows
    @Around("@annotation(com.atguigu.tingshu.common.login.GuiguLogin)")
    public Object LoginAspectMethod(ProceedingJoinPoint joinPoint) {
        // 返回结果初始化
        Object result = null;
        // 获取监听的方法的参数
        Object[] args = joinPoint.getArgs();
        // 方法执行前，获取用户的request请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 请求对象
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取用户携带的token
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            // 没有携带令牌，需要登录
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }
        // 校验token是否合法：是否为私钥生成的token
        try {
            // decodeAndVerify()成功表明Token未篡改、格式正确，可能包含有效签名和过期时间
            Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(SystemConstant.PUBLIC_KEY));
            // 获取载荷
            JSONObject jsonObject = JSON.parseObject(jwt.getClaims());
            // 获取用户id
            Long userId = jsonObject.getLong("userId");
            // 判断token是否过期
            Object o = redisTemplate.opsForValue().get("User_Login_" + userId);
            if (o == null) {
                // 令牌合法但是过期
                log.info("令牌合法但是过期，申请新令牌，申请条件是当前这个旧的token");
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            // TODO 校验设备号：判断用户有没有令牌被盗用
            if (!"123".equals(o.toString())) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }

            // 存储到本地线程
            AuthContextHolder.setUserId(userId);
            Integer isVip = jsonObject.getInteger("isVip");
            AuthContextHolder.setIsVip(isVip);
            Long vipExpireTime = jsonObject.getLong("vipExpireTime");
            AuthContextHolder.setVipExpireTime(vipExpireTime);
            // 方法执行
            result = joinPoint.proceed(args);
            // 返回
            return result;
        } catch (Exception e) {
            // 令牌不合法
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        } finally {
            // 清空本地线程类
            AuthContextHolder.removeUserId();
            AuthContextHolder.removeIsVip();
            AuthContextHolder.removeVipExpireTime();
        }

    }
}
